package gene;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import util.Log;
import base.Item;
import base.Parameter;
import base.ReferenceParameter;
import factory.Schedule;
import geneComponent.Function;
import geneComponent.Node;
import geneComponent.NodeFactory;

public class Gene extends Item implements Cloneable, Schedule.OnCompleteListenner {

	public Gene(Parameter parameters) {

		// maxDepth가 5를 입력 받으면 랜덤하게 2~5 길이(깊이)만큼 Tree를 생성함
		// 따라서 입력 받은 maxDepth를 다시 설정함
		Random random = new Random();
		int minimumValue = 2;
		int randomDepth = random.nextInt((parameters.getValueToInt(Parameter.TYPE_MAX_DEPTH)) - minimumValue + 1) + minimumValue;
		// randomDepth는 입력받은 2~maxDepth까지 생성.
		// maxDepth에 randomDepth를 입력하여 gene을 생성할 때 마다 길이(깊이)가 다른 Tree 생

		setName("Gene");
		maxHeight = randomDepth;
		rootNode = NodeFactory.getRandomNode(randomDepth, parameters.getValueToInt(Parameter.TYPE_DEPTH), parameters.getValueToInt(Parameter.TYPE_ARITY));

	}

	public List<Schedule> scheduleList = new ArrayList<Schedule>();

	private OnCompleteListenner onCompleteListenner;
	
	private Node rootNode;

	private int maxHeight;

	public void setOnCompleteListenner(OnCompleteListenner onCompleteListenner) {
		this.onCompleteListenner = onCompleteListenner;
	}

	public Node getRootNode() {
		return rootNode;
	}

	public void makeAndRunSchedule(int valueToInt, Parameter parameters, List<ReferenceParameter> rpList) {

		for (int i = 0; i < valueToInt; i++) {
			Schedule sc = new Schedule();
			sc.setName("Schedule " + i);
			 sc.setOnCompleteListenner(this);
			sc.scheduleParameter(i, parameters, rpList, this);
			scheduleList.add(sc);
			sc.run();

		}
	}

	public double calculateGene() {

		Function f = (Function) rootNode;
		f.operation();
		return f.getResult();

	}

	public double getAverageFiness() {

		double averageFiness = 0;
		
		for (Schedule sc : scheduleList) {
				averageFiness += sc.getFitness();
		}
		return averageFiness / (scheduleList.size() /*- nullCheck*/);
	}

	public interface OnCompleteListenner {
		public abstract void onComplete(Gene gene);
	}

	@Override
	public void onComplete(Schedule schedule) {
		if (onCompleteListenner == null)
			return;
		onCompleteListenner.onComplete(this);
	}

	public List<Schedule> getScheduleList() {
		return scheduleList;
	}

	public int getMaxHeight() {
		return maxHeight;
	}

	public void setRootNode(Node rootNode) {
		this.rootNode = rootNode;
	}

	public void setScheduleList(List<Schedule> scheduleList) {
		this.scheduleList = scheduleList;
	}
	
	public Object clone() throws CloneNotSupportedException{
		
		return super.clone(); 
	}

		
}
